package com.boat.starter.mockit.service;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.boat.framework.common.thread.context.MockContext;
import com.boat.framework.common.util.JsonUtils;
import com.boat.starter.mockit.annotation.MockRequestQuery;
import com.boat.starter.mockit.props.MockitProperties;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.http.HttpGlobalConfig;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 调用mock服务器服务
 * 
 * @author 周江
 *
 */
@Slf4j
public class MockitCallService {
	private MockitProperties mockitProperties;

	public MockitCallService(MockitProperties mockitProperties) {
		this.mockitProperties = mockitProperties;
	}

	/**
	 * 构造请求query
	 * @param method
	 * @param args
	 * @return
	 */
	public String createQueryStr(Method method, Object[] args) {
		StringBuilder query = new StringBuilder(40);
		query.append("?_from=mockit");

		// 基础类型参数添加到query中
		if (args != null) {
			List<String> parameterNames = getParameterNames(method);
			for (int i = 0; i < args.length; i++) {
				Object arg = args[i];
				if (isSimpleValueType(arg)) {
					String argName = parameterNames.get(i);
					// 如果取不到值，默认使用_p
					argName = argName == null ? "_p" + (i + 1) : argName;
					query.append("&").append(argName).append("=").append(arg);
				}
			}
		}

		return query.toString();
	}

	/**
	 * 获得第一个复杂对象，作为body传输参数
	 * @param args
	 * @return
	 */
	public Object getFirstDtoArg(Object[] args) {
		if (args != null) {
			for (int i = 0; i < args.length; i++) {
				Object arg = args[i];
				if (!isSimpleValueType(arg)) {
					return arg;
				}
			}
		}

		return null;
	}
	
	public boolean isSimpleValueType(Object arg) {
		if (arg == null) {
			return false;
		}
		return ClassUtil.isSimpleValueType(arg.getClass());
	}

	public String postMockReq(String uri, Object param) {
		try {
			String serverAddr = mockitProperties.getServerAddr();
			// 去掉最末尾的/，避免url不存在问题
			if (serverAddr != null && serverAddr.endsWith("/")) {
				serverAddr = serverAddr.substring(0, serverAddr.length() - 1);
			}
			String url = serverAddr + uri;
			String jsonParam = JsonUtils.toJson(param);
			long startTime = System.currentTimeMillis();
			Map<String, String> headers = MockContext.getHeader();
			String result = HttpRequest.post(url).timeout(HttpGlobalConfig.getTimeout()).addHeaders(headers)
					.body(jsonParam).execute().body();

			long times = System.currentTimeMillis() - startTime;
			StringBuilder summary = new StringBuilder(400);
			summary.append("mock服务请求。times: ").append(times).append("ms\n");
			summary.append("path: ").append(url).append("\n");
			summary.append("header: ").append(JsonUtils.toJson(headers)).append("\n");
			summary.append("body: ").append(jsonParam == null ? "" : jsonParam).append("\n");
			summary.append("response: ").append(result);
			log.info(summary.toString());

			// 检查返回结果是否正常
			if (result != null && result.contains("apifoxError")) {
				log.warn("收到mock服务器返回的错误结果，请检查配置是否正确。结果：{}", result);
				throw new RuntimeException("mock服务器返回错误结果");
			}

			return result;
		} catch (Exception ex) {
			log.warn("请求mock服务出错，错误原因：" + ex.getMessage());
			throw new UndeclaredThrowableException(ex);
		}
	}

	public Object buildMockResult(String json, Method method) {
		// 1.用到了泛型包装类
		Type genericReturnType = method.getGenericReturnType();
		if (genericReturnType instanceof ParameterizedType) {
			//return JSONUtil.toBean(json, genericReturnType, false);
			//忽略字段大小写
			return JSONUtil.parse(json, JSONConfig.create().setIgnoreCase(true).setIgnoreError(false))
					.toBean(genericReturnType);
		}

		// 2.没有用到包装类，简单填充
		Class<?> methodReturnType = method.getReturnType();
		return JSONUtil.toBean(json, methodReturnType);
	}

	private List<String> getParameterNames(Method method) {
		List<String> paramNames = new ArrayList<>(10);
		try {
//			// 1.支持写法：Parameters-Parameter
//			Parameters parameters = AnnotationUtils.getAnnotation(method, Parameters.class);
//			if (parameters != null && parameters.value() != null) {
//				for (Parameter parameter : parameters.value()) {
//					paramNames.add(parameter.name());
//				}
//				return paramNames;
//			}
//
//			// 2.支持写法：参数中带Parameter
//			Annotation[][] annotations = method.getParameterAnnotations();
//			if (annotations != null && annotations.length > 0) {
//				for (int i = 0; i < annotations.length; i++) {
//					for (int j = 0; j < annotations[i].length; j++) {
//						if (annotations[i][j] instanceof Parameter) {
//							Parameter parameter = (Parameter) annotations[i][j];
//							paramNames.add(parameter.name());
//						}
//					}
//				}
//			}
//
//			// 3.支持写法：@Operation - Parameters - Parameter
//			Operation operation = AnnotationUtils.getAnnotation(method, Operation.class);
//			if (operation != null && operation.parameters() != null && operation.parameters().length > 0) {
//				for (Parameter parameter : operation.parameters()) {
//					paramNames.add(parameter.name());
//				}
//				return paramNames;
//			}
			
			
			// 4.支持写法：参数中带MockRequestParam
			Annotation[][] annotations = method.getParameterAnnotations();
			if (annotations != null && annotations.length > 0) {
				for (int i = 0; i < annotations.length; i++) {
					for (int j = 0; j < annotations[i].length; j++) {
						if (annotations[i][j] instanceof MockRequestQuery) {
							MockRequestQuery mockRequestParam = (MockRequestQuery) annotations[i][j];
							paramNames.add(mockRequestParam.name());
						}
					}
				}
			}
			
			// 5.未设置参数名称，直接使用p
			for (int i = 0; i < method.getParameterCount(); i++) {
				paramNames.add("_p" + (i + 1));
			}
			return paramNames;
		} catch (Exception ex) {
			throw new UndeclaredThrowableException(ex);
		}
	}
}
